<?php 
/**
 * 请求管理类
 * 
 * Copyright (c) 2014~2019 https://desion.net All rights reserved.
 * Author: 阿林 QQ:120867629 <linhong00@gmail.com>
 */
declare (strict_types = 1);
namespace dsphp;
use dsphp\Upload;
use dsphp\http\Request;
use dsphp\http\Response;
use dsphp\http\Input;

class Http
{
    use Request,Response,Input;
    // PATHINFO变量名 用于兼容模式
    protected $varPathinfo = 's';
    // 表单ajax伪装变量
    protected $varAjax = '_ajax';
    // HOST（含端口）
    protected $host;
    // 当前URL地址
    protected $url;
    // pathinfo
    protected $pathinfo;
    // 当前请求的IP地址
    protected $realIP;
    // 当前请求参数
    protected $param = [];
    // 当前PUT参数
    protected $put = [];   
    // 当前GET参数
    protected $get = [];
    // 当前POST参数
    protected $post = [];
    // COOKIE数据
    protected $cookie = [];
    // SESSION数据
    protected $session = [];
    // 当前SERVER参数
    protected $server = [];
    // 当前FILE参数
    protected $file = [];
    // 当前HEADER参数
    protected $header  = [];
    // 全局过滤规则
    protected $filter;
    // php://input
    protected $input;


    /**
     * 架构函数
     */
    public function __construct()
    {
        // 读取请求各类信息
        $this->_initRequest();
        // response 页面输出类型
        $this->_initResponse();
    }

    /**
     * 发送结果
     */
    public function send($content):void
    {
        $headers = $this->getHeader();

        if (! headers_sent() && ! empty($headers)) {
            // 发送状态码
            http_response_code($this->code);
            // 发送头部信息（response）
            foreach ($headers as $name => $val) {
                header($name . (!is_null($val) ? ':' . $val : ''));
            }
        }

        echo $content;

        if (function_exists('fastcgi_finish_request')) {
            // 提高页面响应
            fastcgi_finish_request();
        }
    }

    /**
     * 获取当前请求URL的pathinfo信息
     *
     * @return string
     */
    public function pathinfo($ext = true): string
    {
        if (isset($_GET[$this->varPathinfo])) {
            $pathinfo = $_GET[$this->varPathinfo];
            unset($_GET[$this->varPathinfo]);
            unset($this->get[$this->varPathinfo]);
        } elseif ($this->server('PATH_INFO')) {
            $pathinfo = $this->server('PATH_INFO');
        } elseif ('cli-server' == PHP_SAPI) {
            $pathinfo = strpos($this->server('REQUEST_URI'), '?') ? strstr($this->server('REQUEST_URI'), '?', true) : $this->server('REQUEST_URI');
        }

        // 分析PATHINFO信息
        if (! isset($pathinfo)) {
            // 兼容PATH_INFO获取
            $pathinfoFetch = ['ORIG_PATH_INFO', 'REDIRECT_PATH_INFO', 'REDIRECT_URL'];

            foreach ($pathinfoFetch as $type) {
                if ($this->server($type)) {
                    $pathinfo = (0 === strpos($this->server($type), $this->server('SCRIPT_NAME'))) ?
                    substr($this->server($type), strlen($this->server('SCRIPT_NAME'))) : $this->server($type);
                    break;
                }
            }
        }

        if (! empty($pathinfo)) {
            unset($this->get[$pathinfo]);
        }

        $pathinfo = empty($pathinfo) || '/' == $pathinfo ? '' : trim($pathinfo, '/');

        if ($ext === false) {
            $pathinfo = preg_replace('/\.html$/i', '', $pathinfo);
        }

        $this->pathinfo = $pathinfo;

        return $pathinfo;
    }

    /**
     * 获取客户端IP地址
     */
    public function ip(): string
    {
        if (! empty($this->realIP)) {
            return $this->realIP;
        }

        $this->realIP = $this->server('REMOTE_ADDR', '');
        // 则尝试获取前端代理服务器发送过来的真实IP
        $proxyIpHeader = ['HTTP_X_REAL_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_CLIENT_IP', 'HTTP_X_CLIENT_IP', 'HTTP_X_CLUSTER_CLIENT_IP'];

        if (count($proxyIpHeader) > 0) {
            // 从指定的HTTP头中依次尝试获取IP地址
            // 直到获取到一个合法的IP地址
            foreach ($proxyIpHeader as $header) {
                $tempIP = $this->server($header);

                if (empty($tempIP)) {
                    continue;
                }

                $tempIP = trim(explode(',', $tempIP)[0]);

                if (! $this->isValidIP($tempIP)) {
                    $tempIP = null;
                } else {
                    $this->realIP = $tempIP;
                    break;
                }
            }
            // tempIP不为空，说明获取到了一个IP地址
            // 这时我们检查 REMOTE_ADDR 是不是指定的前端代理服务器之一
            // 如果是的话说明该 IP头 是由前端代理服务器设置的
            // 否则则是伪装的
            // if (! empty($tempIP)) {
            //     $realIPBin = $this->ip2bin($this->realIP);
            // }
        }

        if (! $this->isValidIP($this->realIP)) {
            $this->realIP = '0.0.0.0';
        }

        return $this->realIP;
    }

    /**
     * 检测是否是合法的IP地址
     *
     * @param string $ip   IP地址
     * @param string $type IP地址类型 (ipv4, ipv6)
     */
    public function isValidIP(string $ip, string $type = ''): bool
    {
        switch (strtolower($type)) {
            case 'ipv4':
                $flag = FILTER_FLAG_IPV4;
                break;
            case 'ipv6':
                $flag = FILTER_FLAG_IPV6;
                break;
            default:
                $flag = null;
                break;
        }

        return boolval(filter_var($ip, FILTER_VALIDATE_IP, $flag));
    }

    /**
     * 将IP地址转换为二进制字符串
     *
     * @param string $ip
     */
    public function ip2bin(string $ip): string
    {
        if ($this->isValidIP($ip, 'ipv6')) {
            $IPHex = str_split(bin2hex(inet_pton($ip)), 4);
            foreach ($IPHex as $key => $value) {
                $IPHex[$key] = intval($value, 16);
            }
            $IPBin = vsprintf('%016b%016b%016b%016b%016b%016b%016b%016b', $IPHex);
        } else {
            $IPHex = str_split(bin2hex(inet_pton($ip)), 2);
            foreach ($IPHex as $key => $value) {
                $IPHex[$key] = intval($value, 16);
            }
            $IPBin = vsprintf('%08b%08b%08b%08b', $IPHex);
        }

        return $IPBin;
    }

    /**
     * 检测是否使用手机访问
     */
    public function isMobile(): bool
    {
        if ($this->server('HTTP_VIA') && stristr($this->server('HTTP_VIA'), "wap")) {
            return true;
        } elseif ($this->server('HTTP_ACCEPT') && strpos(strtoupper($this->server('HTTP_ACCEPT')), "VND.WAP.WML")) {
            return true;
        } elseif ($this->server('HTTP_X_WAP_PROFILE') || $this->server('HTTP_PROFILE')) {
            return true;
        } elseif ($this->server('HTTP_USER_AGENT') && preg_match('/(blackberry|configuration\/cldc|hp |hp-|htc |htc_|htc-|iemobile|kindle|midp|mmp|motorola|mobile|nokia|opera mini|opera |Googlebot-Mobile|YahooSeeker\/M1A1-R2D2|android|iphone|ipod|mobi|palm|palmos|pocket|portalmmm|ppc;|smartphone|sonyericsson|sqh|spv|symbian|treo|up.browser|up.link|vodafone|windows ce|xda |xda_)/i', $this->server('HTTP_USER_AGENT'))) {
            return true;
        }

        return false;
    }

    /**
     * URL生成
     *
     * @param string $url    路由地址
     * @param array  $vars   注入参数（注意顺序） ['val1', 'b'=>'val2']
     * @param array  $vars   get参数 ['a'=>'val1', 'b'=>'val2']
     * @param array  $domain 域名，为空则自动
     */
    public function url(string $url, array $bind = [], array $vars = [], string $domain = '/'):string
    {
        foreach ($bind as $val) {
            $url .= '/'.$val;
        }

        $domain = $domain ?: '/';

        $url .= '.html';
        $vars && $url .= '?'.http_build_query($vars);
        
        return  $domain . $url;
    }
}